<template>
    <div class="m-3d">
      <ul class="stack">
        <li
          v-for="(item, index) in tier"
          class="stack-item"
          :style="[transformIndex(index),transform(index)]"
          @touchstart.stop.prevent="touchstart"
          @touchmove.stop.prevent="touchmove"
          @touchend.stop.prevent="touchend"
          @mousedown.stop.prevent="touchstart"
          @mousemove.stop.prevent="touchmove"
          @mouseup.stop.prevent="touchend"
          @webkit-transition-end="onTransitionEnd(index)"
          @transitionend="onTransitionEnd(index)"
        >
          <div v-html="item.html"></div>
        </li>
      </ul>
    </div>
</template>
<style lang="less">
.m-3d {
  width: 320px;
  height: 320px;
  z-index: 1000;
  position: relative;
  /*pointer-events: none; !*元素永远不会成为鼠标事件的target*!*/
  padding: 300px 0;
  margin: 0 auto;
  .stack {
    position: relative;
    width: 100%;
    height: 100%;
    perspective: 1000px; /*子元素视距*/
    perspective-origin: 50% 150%; /*子元素透视位置*/
    margin: 0;
    padding: 0;
      .stack-item {
        position: absolute;
        background: #fff;
        width: 100%;
        height: 100%;
        border-radius: 4px;
        text-align: center;
        opacity: 0;
        overflow: hidden;
        img {
          display: block;
          width: 100%;
          pointer-events: none; /*元素永远不会成为鼠标事件的target*/
        }
      }
  }
}
</style>
<script>
  import detectPrefixes from '../../unit/detect-prefixes.js'
  export default {
    data () {
      return {
        tier: [],//显示的内容
        razer: {
          start: {
            t: 0,
            x: 0,
            y: 0
          },
          end: {
            x: 0,
            y: 0
          }
        },//保存鼠标或手势的起始和结束位置
        options: {
          visible: 3,//表示只显示3张
          currentPage: 0,//当前显示第几张卡片
          lastPosWidth: 0,//记录鼠标手势放掉时的位移
          lastPosHeight: 0,//记录鼠标手势放掉时的位移
          lastOpacity: 0,//当前卡片上一张的透明度
          opacity: 1,//首张卡片的透明度
          poswidth: 0,//鼠标或手势移动的距离
          posheight: 0,//鼠标或手势移动的距离
          swipe: false,//用来判断是否执行上下层的动画的
          animation: false,//移动动画的执行
          tracking: false,//手势或鼠标不可点击
          prefixes: detectPrefixes()//用于兼容
        }//配置项
      }
    },
    methods: {
      touchstart (e) {
        if(this.options.tracking) return
        if(e.type === 'touchstart') {
          if(e.touches.length > 1) {//大于2个手指时 可以手势 但是不会执行下面的事件
            this.options.tracking = false;
            return
          }else {
            //记录起始位置
            let targetTouches = e.targetTouches[0];
            this.razer.start.t = new Date().getTime();
            this.razer.start.x = targetTouches.clientX;
            this.razer.start.y = targetTouches.clientY;
            this.razer.end.x = targetTouches.clientX;
            this.razer.end.y = targetTouches.clientY;
          }
        }else {//PC
          this.razer.start.t = new Date().getTime();
          this.razer.start.x = e.clientX;
          this.razer.start.y = e.clientY;
          this.razer.end.x = e.clientX;
          this.razer.end.y = e.clientY;
        }
        this.options.tracking = true;//初始化可以再次点击或手势
        this.options.animation = false;//动画关闭
      },
      touchmove (e) {
        if(this.options.tracking && !this.options.animation) {//可以手势并且动画关闭
          if (e.type === 'touchmove') {
            this.razer.end.x = e.targetTouches[0].clientX;
            this.razer.end.y = e.targetTouches[0].clientY;
          } else {
            this.razer.end.x = e.clientX
            this.razer.end.y = e.clientY
          }
          //计算移动值
          this.options.poswidth = this.razer.end.x - this.razer.start.x;//向左右移动的距离
          this.options.posheight = this.razer.end.y - this.razer.start.y;//向上下移动的距离
        }
      },
      touchend (e) {
        this.options.tracking = false;//初始化
        this.options.animation = true;//开启动画
        if(Math.abs(this.options.poswidth) >= 100) {
          let ratio = Math.abs(this.options.posheight / this.options.poswidth);//移动距离的比例
          this.options.poswidth = this.options.poswidth >= 0 ? this.options.poswidth + 200 : this.options.poswidth - 200;
          //计算移动的距离并判断是向左还是向右，根据移动的方向做动画效果
          this.options.posheight = this.options.posheight >= 0 ? Math.abs(this.options.poswidth * ratio) : -Math.abs(this.options.poswidth * ratio);
          //计算移动的距离判断是上还是下,根据与X轴移动距离的比例判断移动的方向
          this.options.opacity = 0;
          //渐渐消失
          this.options.swipe = true;
          // 记录最终滑动距离
          this.options.lastPosWidth = this.options.poswidth;
          this.options.lastPosHeight = this.options.posheight;
          if(this.options.currentPage === this.tier.length - 1){
            this.options.currentPage = 0
          }else {
            this.options.currentPage += 1;//当前卡片变化
          }
          // currentPage切换，整体dom进行变化，把第一层滑动置零
          this.$nextTick(() => {
            this.options.poswidth = 0;
            this.options.posheight = 0;
            this.options.opacity = 1;
          })
          //数据初始化
        }else {
          this.options.poswidth = 0;//初始化
          this.options.posheight = 0;//初始化
          this.options.swipe = false;//不执行上下层级的动画
        }
      },
      onTransitionEnd (i) {
        // dom发生变化正在执行的动画滑动序列已经变为上一层
        if (this.options.swipe && i === this.options.currentPage - 1) {
          this.options.animation = true;//动画执行
          this.options.lastPosWidth = 0;//初始记录的
          this.options.lastPosHeight = 0;//初始记录的
          this.options.lastOpacity = 0;//初始记录的
          this.options.swipe = false;
        }
      },//滑动动画结束时上下层级动画的切换
      transform (i) {
        if(i > this.options.currentPage) {//当前下标大于首张卡片的下标
          let style = {};//输出的样式
          let visible = this.options.visible;//显示的个数
          let perIndex = i - this.options.currentPage;//当前下标与当前卡片下标的相差值
          if(i < this.options.currentPage + visible) {//当前卡片后面2张的样式
            style['transform'] = `translate3D(0, 0, ${-perIndex * 60}px)`;//Z轴的层级
            style['opacity'] = 1;
            style['zIndex'] = this.options.currentPage + visible - i ;//当前卡片下标 + 显示个数 - 当前卡片后面2张卡片的下标(层级递减)
            style[`${this.options.prefixes.transition}TimingFunction`] = 'ease';//设置动画的方式
            style[`${this.options.prefixes.transition}Duration`] = 300 + 'ms'//设置动画的时间
          }else {//(2张以后的样式)
            style['transform'] = `translate3D(0, 0, ${-visible * 60}px)`;
            style['zIndex'] = -1;//层级往下
          }
          return style
        }else if(i === this.options.currentPage - 1){//当前卡片的上一张卡片的样式和动画
          let style = {}
          style['transform'] = `translate3D(${this.options.lastPosWidth}px, ${this.options.lastPosHeight}px, -${(this.tier.length-1) * 60}px)`;
          style['opacity'] = this.options.lastOpacity;//透明度为0
          style['zIndex'] = -1;//层级往下
          style[`${this.options.prefixes.transition}TimingFunction`] = 'ease';//动画方式
          style[`${this.options.prefixes.transition}Duration`] = `300ms`;//动画时间
          return style
        }else if(i !== this.options.currentPage){
          let style = {}
          style['transform'] = `translate3D(${this.options.lastPosWidth}px, ${this.options.lastPosHeight}px, -300px)`;
          //当前下标减去卡片代表的下标
          style['opacity'] = 0;//透明度为0
          style['zIndex'] = -1;//层级往下
          return style
        }
      },//不是首张卡片样式
      transformIndex (i) {//当前首张卡片Z轴上升
        let style = {};
        if(i === this.options.currentPage) {
          style['transform'] = `translate3D(${this.options.poswidth}px, ${this.options.posheight}px, 0px)`;
          style['opacity'] = this.options.opacity;
          style['zIndex'] = 10;
          if (this.options.animation) {
            style[`${this.options.prefixes.transition}TimingFunction`] = 'ease';
            style[`${this.options.prefixes.transition}Duration`] = `${this.options.animation ? 300 : 0}ms`;
          }
          return style
        }
      }//首张卡片样式
    },
    mounted () {
      for(let i =1; i < 7; i++) {
        this.tier.push({
          html: `<img src="${require(`../../assets/image/${i}.png`)}">`
        })
      }
    }
  }
</script>
